/*
HTTP Simple Queue Service - akqueue v0.6
Author: Niu Guang Ju, E-mail: v_niuguangju@baidu.com
This is free software, and you are welcome to modify and redistribute it under the New BSD License
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <tcbdb.h>
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <event.h>
#include <evhttp.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include "prename.h"
#define VERSION "0.6"

//每个队列的默认最大长度为100万条
#define akqueue_DEFAULT_MAXQUEUE 1000000

//全局设置
TCBDB *akqueue_tcbdb; //数据表
int   akqueue_syncinterval; //同步更新内容到磁盘的间隔时间
char  *akqueue_pidfile; //PID文件
char  *akqueue_auth; //验证密码

//创建多层目录
void akqueue_mkdir(char *pathname)
{
	int    i,len;
	char    str[512];

	strncpy(str, pathname, 512);
	len=strlen(str);
	for(i=0; i<len; i++)
	{
		if(str[i]=='/')
		{
			str[i] = '\0';
			//判断此目录是否存在,不存在则创建
			if(access(str, F_OK)!=0)
			{
				mkdir(str, 0777);
			}
			str[i]='/';
		}
	}
	if(len>0 && access(str, F_OK)!=0)
	{
		mkdir(str, 0777);
	}

	return;
}

static void akqueue_show_menu(void)
{
	char *b = "--------------------------------------------------------------------------------------------------\n"
	          "HTTP Queue Service - akqueue v" VERSION " (November 20, 2012)\n\n"
	          "Author: Niu GuangJu, E-mail: v_niuguangju@baidu.com\n"
	          "This is free software, and you are welcome to modify and redistribute it under the New BSD License\n"
	          "\n"
	          "-l <ip_addr>  interface to listen on, default is 0.0.0.0\n"
	          "-p <num>      TCP port number to listen on (default: 1218)\n"
	          "-x <path>     datafile directory (example: /opt/akqueue/data)\n"
	          "-t <second>   keep-alive timeout for an http request (default: 60)\n"
	          "-s <second>   the interval to sync updated contents to the disk (default: 5)\n"
	          "-c <num>      the maximum number of non-leaf nodes to be cached (default: 1024)\n"
	          "-m <size>     database memory cache size in MB (default: 100)\n"
	          "-i <file>     save PID in <file> (default: /tmp/akqueue.pid)\n"
	          "-a <auth>     the auth password to access akqueue (example: mypass123)\n"
	          "-d            run as a daemon\n"
	          "-h            print this help and exit\n\n"
	          "Use command \"killall akqueue\", \"pkill akqueue\" and \"kill `cat /tmp/akqueue.pid`\" to stop akqueue.\n"
	          "Please note that don't use the command \"pkill -9 akqueue\" and \"kill -9 PID of akqueue\"!\n"
	          "\n"
	          "Please visit \"http://code.google.com/p/akqueue\" for more help information.\n\n"
	          "--------------------------------------------------------------------------------------------------\n"
	          "\n";
	fprintf(stderr, b, strlen(b));
}

//父进程信号处理
static void kill_signal_master(const int sig)
{
	//删除PID文件
	remove(akqueue_pidfile);

	//给进程组发送SIGTERM信号，结束子进程
	kill(0, SIGTERM);

	exit(0);
}

//子进程信号处理
static void kill_signal_worker(const int sig)
{

	fprintf(stderr, "tcbdbsync:%d\n", sig);

	//同步内存数据到磁盘，并关闭数据库
	tcbdbsync(akqueue_tcbdb);
	tcbdbclose(akqueue_tcbdb);
	tcbdbdel(akqueue_tcbdb);

	exit(0);
}

//定时同步线程，定时将内存中的内容写入磁盘
static void sync_worker(const int sig)
{
	pthread_detach(pthread_self());

	while(1)
	{
		//间隔httpsqs_settings_syncinterval秒同步一次数据到磁盘
		sleep(akqueue_syncinterval);

		//同步内存数据到磁盘
		tcbdbsync(akqueue_tcbdb);
	}
}

char *urldecode(char *input_str)
{
	int len = strlen(input_str);
	char *str = strdup(input_str);

	char *dest = str;
	char *data = str;

	int value;
	int c;

	while (len--)
	{
		if (*data == '+')
		{
			*dest = ' ';
		}
		else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1))
		         && isxdigit((int) *(data + 2)))
		{

			c = ((unsigned char *)(data+1))[0];
			if (isupper(c))
				c = tolower(c);
			value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
			c = ((unsigned char *)(data+1))[1];
			if (isupper(c))
				c = tolower(c);
			value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;

			*dest = (char)value ;
			data += 2;
			len -= 2;
		}
		else
		{
			*dest = *data;
		}
		data++;
		dest++;
	}
	*dest = '\0';
	return str;
}

//读取用于设置的最大队列数
static int akqueue_read_maxqueue(const char* name)
{
	int queue_value = 0;
	char *queue_value_tmp;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	sprintf(queue_name, "%s:%s", name, "maxqueue");

	queue_value_tmp = tcbdbget2(akqueue_tcbdb, queue_name);

	if(queue_value_tmp)
	{
		queue_value = atoi(queue_value_tmp);
		free(queue_value_tmp);
	}
	else
	{
		queue_value = akqueue_DEFAULT_MAXQUEUE; //默认队列长度
	}

	return queue_value;
}

//读取队列写入点的值
static int akqueue_read_putpos(const char* name)
{
	int queue_value = 0;
	char *queue_value_tmp;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	sprintf(queue_name, "%s:%s", name, "putpos");

	queue_value_tmp = tcbdbget2(akqueue_tcbdb, queue_name);
	if(queue_value_tmp)
	{
		queue_value = atoi(queue_value_tmp);
		free(queue_value_tmp);
	}

	return queue_value;
}

//读取队列读取点的值
static int akqueue_read_getpos(const char* name)
{
	int queue_value = 0;
	char *queue_value_tmp;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	sprintf(queue_name, "%s:%s", name, "getpos");

	queue_value_tmp = tcbdbget2(akqueue_tcbdb, queue_name);

	if(queue_value_tmp)
	{
		queue_value = atoi(queue_value_tmp);
		free(queue_value_tmp);
	}

	return queue_value;
}

//获取本次"入队列"操作的队列写入点
static int akqueue_now_putpos(const char* name)
{
	int maxqueue_num = 0;
	int queue_put_value = 0;
	int queue_get_value = 0;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节
	char queue_input[32] = {0};

	//获取最大队列数量
	maxqueue_num = akqueue_read_maxqueue(name);

	//读取当前队列写入位置点
	queue_put_value = akqueue_read_putpos(name);

	//读取当前队列读取位置点
	queue_get_value = akqueue_read_getpos(name);

	sprintf(queue_name, "%s:%s", name, "putpos");

	//队列写入位置点加
	queue_put_value = queue_put_value + 1;
	if(queue_put_value == queue_get_value)   //如果队列写入ID+1之后追上队列读取ID，则说明队列已满，返回0，拒绝继续写入
	{
		queue_put_value = 0;
	}
	else if(queue_get_value <= 1 && queue_put_value > maxqueue_num)   //如果队列写入ID大于最大队列数量，并且从未进行过出队列操作（=0）或进行过1次出队列操作（=1），返回0，拒绝继续写入
	{
		queue_put_value = 0;
	}
	else if(queue_put_value > maxqueue_num)   //如果队列写入ID大于最大队列数量，则重置队列写入位置点的值为1
	{
		if(tcbdbput2(akqueue_tcbdb, queue_name, "1"))
		{
			queue_put_value = 1;
		}
	}
	else     //队列写入位置点加1后的值，回写入数据库
	{
		sprintf(queue_input, "%d", queue_put_value);
		tcbdbput2(akqueue_tcbdb, queue_name, (char *)queue_input);
	}

	return queue_put_value;
}

//获取本次"出队列"操作的队列读取点，返回值为0时队列全部读取完成
static int akqueue_now_getpos(const char* name)
{
	int maxqueue_num = 0;
	int queue_put_value = 0;
	int queue_get_value = 0;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	//获取最大队列数量
	maxqueue_num = akqueue_read_maxqueue(name);

	//读取当前队列写入位置点
	queue_put_value = akqueue_read_putpos(name);

	//读取当前队列读取位置点
	queue_get_value = akqueue_read_getpos(name);

	//如果queue_get_value的值不存在，重置队列读取位置点为1
	sprintf(queue_name, "%s:%s", name, "getpos");
	//如果queue_get_value的值不存在，重置为1
	if(queue_get_value == 0 && queue_put_value > 0)
	{
		queue_get_value = 1;
		tcbdbput2(akqueue_tcbdb, queue_name, "1");
		//如果队列的读取值（出队列）小于队列的写入值（入队列）
	}
	else if (queue_get_value < queue_put_value)
	{
		queue_get_value = queue_get_value + 1;
		char queue_input[32] = {0};
		sprintf(queue_input, "%d", queue_get_value);
		tcbdbput2(akqueue_tcbdb, queue_name, queue_input);
		//如果队列的读取值（出队列）大于队列的写入值（入队列），并且队列的读取值（出队列）小于最大队列数量
	}
	else if (queue_get_value > queue_put_value && queue_get_value < maxqueue_num)
	{
		queue_get_value = queue_get_value + 1;
		char queue_input[32] = {0};
		sprintf(queue_input, "%d", queue_get_value);
		tcbdbput2(akqueue_tcbdb, queue_name, queue_input);
		//如果队列的读取值（出队列）大于队列的写入值（入队列），并且队列的读取值（出队列）等于最大队列数量
	}
	else if (queue_get_value > queue_put_value && queue_get_value == maxqueue_num)
	{
		queue_get_value = 1;
		tcbdbput2(akqueue_tcbdb, queue_name, "1");
		//队列的读取值（出队列）等于队列的写入值（入队列），即队列中的数据已全部读出
	}
	else
	{
		queue_get_value = 0;
	}

	return queue_get_value;
}

//查看单条队列内容
char *akqueue_view(const char* name, int pos)
{
	char *queue_value;
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	sprintf(queue_name, "%s:%d", name, pos);

	queue_value = tcbdbget2(akqueue_tcbdb, queue_name);

	return queue_value;
}

//重置队列，0表示重置成功
static int akqueue_reset(const char* name)
{
	char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节

	sprintf(queue_name, "%s:%s", name, "putpos");
	tcbdbout2(akqueue_tcbdb, queue_name);

	memset(queue_name, '\0', 300);
	sprintf(queue_name, "%s:%s", name, "getpos");
	tcbdbout2(akqueue_tcbdb, queue_name);

	memset(queue_name, '\0', 300);
	sprintf(queue_name, "%s:%s", name, "maxqueue");
	tcbdbout2(akqueue_tcbdb, queue_name);

	tcbdbsync(akqueue_tcbdb); //实时刷新到磁盘

	return 0;
}

//设置最大的队列数量
static int akqueue_maxqueue(const char* name, int num)
{
	int queue_put_value = 0;
	int queue_get_value = 0;
	int queue_maxnum_int = 0;

	//读取当前队列写入位置点
	queue_put_value = akqueue_read_putpos(name);

	//读取当前队列读取位置点
	queue_get_value = akqueue_read_getpos(name);

	//设置最大的队列数量，最小值为10条，最大值为10亿条
	queue_maxnum_int = num;

	//设置的最大的队列数量必须大于等于”当前队列写入位置点“和”当前队列读取位置点“，并且”当前队列写入位置点“必须大于等于”当前队列读取位置点“
	if(queue_maxnum_int >= queue_put_value && queue_maxnum_int >= queue_get_value && queue_put_value >= queue_get_value)
	{
		char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节
		char queue_maxnum[16] = {0};
		sprintf(queue_name, "%s:%s", name, "maxqueue");
		sprintf(queue_maxnum, "%d", queue_maxnum_int);
		tcbdbput2(akqueue_tcbdb, queue_name, queue_maxnum);

		tcbdbsync(akqueue_tcbdb); //实时刷新到磁盘

		return 1;
	}

	return 0;
}


//修改定时更新内存内容到磁盘的间隔时间
static int akqueue_synctime(int num)
{
	if (num >= 1)
	{
		akqueue_syncinterval = num;
		return 1;
	}
	return 0;
}

//处理模块
void http_handler(struct evhttp_request *req, void *arg)
{
	struct evbuffer *buf = evbuffer_new();

	//分析URL参数
	const char *q;
	struct evkeyvalq h;
	q = evhttp_uri_get_query(req->uri_elems);
	evhttp_parse_query_str(q, &h);

	/* 接收GET表单参数 */
	const char *auth = evhttp_find_header(&h, "auth"); //队列名称
	const char *name = evhttp_find_header(&h, "name"); //队列名称
	const char *charset = evhttp_find_header(&h, "charset"); //操作类别
	const char *opt = evhttp_find_header(&h, "opt"); //操作类别
	const char *data = evhttp_find_header(&h, "data"); //操作类别
	const char *pos_tmp = evhttp_find_header(&h, "pos"); //队列位置点
	const char *num_tmp = evhttp_find_header(&h, "num"); //队列总长度
	int pos = 0;
	int num = 0;

	//返回给用户的Header头信息
	if(charset != NULL && strlen(charset) <= 40)
	{
		char content_type[64] = {0};
		sprintf(content_type, "text/plain; charset=%s", charset);
		evhttp_add_header(req->output_headers, "Content-Type", content_type);
	}
	else
	{
		evhttp_add_header(req->output_headers, "Content-Type", "text/plain");
	}
	evhttp_add_header(req->output_headers, "Connection", "keep-alive");
	evhttp_add_header(req->output_headers, "Cache-Control", "no-cache");

	//权限校验
	bool is_auth_pass = false; //是否验证通过
	if(akqueue_auth != NULL)
	{
		//如果命令行启动参数设置了验证密码
		if (auth != NULL && strcmp(akqueue_auth, auth) == 0)
		{
			is_auth_pass = true;
		}
		else
		{
			is_auth_pass = false;
		}
	}
	else
	{
		//如果命令行启动参数没有设置验证密码
		is_auth_pass = true;
	}

	if(is_auth_pass == false)
	{
		//校验失败
		evbuffer_add_printf(buf, "%s", "AKQUEUE_AUTH_FAILED");
	}
	else
	{
		//校验成功，或者命令行启动参数没有设置校验密码
		if(pos_tmp)
		{
			pos = atoi(pos_tmp); //队列位置点
		}
		if(num_tmp)
		{
			num = atoi(num_tmp); //队列总长度
		}

		//判断参数是否存在
		if (name && opt && strlen(name) <= 256)
		{
			//入队列
			if(strcmp(opt, "put") == 0)
			{
				//优先接收POST正文信息
				int buffer_data_len;
				buffer_data_len = EVBUFFER_LENGTH(req->input_buffer);
				if(buffer_data_len > 0)
				{
					int queue_put_value = akqueue_now_putpos((char *)name);

					if(queue_put_value > 0)
					{
						char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节
						sprintf(queue_name, "%s:%d", name, queue_put_value);
						char *postbuffer;
						char *buffer_data = (char *)tccalloc(1, buffer_data_len + 1);
						memcpy(buffer_data, EVBUFFER_DATA(req->input_buffer), buffer_data_len);
						postbuffer = urldecode(buffer_data);
						tcbdbput2(akqueue_tcbdb, queue_name, postbuffer);
						memset(queue_name, '\0', 300);
						sprintf(queue_name, "%d", queue_put_value);
						evhttp_add_header(req->output_headers, "Pos", queue_name);
						evbuffer_add_printf(buf, "%s", "HTTPSQS_PUT_OK");
						free(postbuffer);
						free(buffer_data);
					}
					else
					{
						evbuffer_add_printf(buf, "%s", "HTTPSQS_PUT_END");
					}
					//如果POST正文无内容，则取URL中data参数的值
				}
				else if(data)
				{
					int queue_put_value = akqueue_now_putpos((char *)name);
					if (queue_put_value > 0)
					{
						char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节
						sprintf(queue_name, "%s:%d", name, queue_put_value);
						buffer_data_len = strlen(data);
						char *postbuffer;
						char *buffer_data = (char *)tccalloc(1, buffer_data_len + 1);
						memcpy (buffer_data, data, buffer_data_len);
						postbuffer = urldecode(buffer_data);
						tcbdbput2(akqueue_tcbdb, queue_name, postbuffer);
						memset(queue_name, '\0', 300);
						sprintf(queue_name, "%d", queue_put_value);
						evhttp_add_header(req->output_headers, "Pos", queue_name);
						evbuffer_add_printf(buf, "%s", "AKQUEUE_PUT_OK");
						free(postbuffer);
						free(buffer_data);
					}
					else
					{
						evbuffer_add_printf(buf, "%s", "AKQUEUE_PUT_END");
					}
				}
				else
				{
					evbuffer_add_printf(buf, "%s", "AKQUEUE_PUT_ERROR");
				}
			}

			//出队列
			else if(strcmp(opt, "get") == 0)
			{
				int queue_get_value = 0;
				queue_get_value = akqueue_now_getpos((char *)name);

				evbuffer_add_printf(buf, "%d", queue_get_value);

				if(queue_get_value == 0)
				{
					evbuffer_add_printf(buf, "%s", "AKQUEUE_GET_END");
				}
				else
				{
					char queue_name[300] = {0}; //队列名称的总长度，用户输入的队列长度少于256字节
					sprintf(queue_name, "%s:%d", name, queue_get_value);
					char *output_value;
					output_value = tcbdbget2(akqueue_tcbdb, queue_name);
					if(output_value)
					{
						memset(queue_name, '\0', 300);
						sprintf(queue_name, "%d", queue_get_value);
						evhttp_add_header(req->output_headers, "Pos", queue_name);
						evbuffer_add_printf(buf, "%s", output_value);
						free(output_value);
					}
					else
					{
						evbuffer_add_printf(buf, "%s", "AKQUEUE_GET_END");
					}
				}
			}

			//查看队列状态（普通浏览方式）
			else if (strcmp(opt, "status") == 0)
			{
				int maxqueue = akqueue_read_maxqueue((char *)name); //最大队列数量
				int putpos = akqueue_read_putpos((char *)name); //入队列写入位置
				int getpos = akqueue_read_getpos((char *)name); //出队列读取位置
				int ungetnum;
				const char *put_times;
				const char *get_times;
				if (putpos >= getpos)
				{
					ungetnum = abs(putpos - getpos); //尚未出队列条数
					put_times = "1st lap";
					get_times = "1st lap";
				}
				else if (putpos < getpos)
				{
					ungetnum = abs(maxqueue - getpos + putpos); //尚未出队列条数
					put_times = "2nd lap";
					get_times = "1st lap";
				}
				evbuffer_add_printf(buf, "AKQUEUE v%s\n", VERSION);
				evbuffer_add_printf(buf, "------------------------------\n");
				evbuffer_add_printf(buf, "Queue Name: %s\n", name);
				evbuffer_add_printf(buf, "Maximum number of queues: %d\n", maxqueue);
				evbuffer_add_printf(buf, "Put position of queue (%s): %d\n", put_times, putpos);
				evbuffer_add_printf(buf, "Get position of queue (%s): %d\n", get_times, getpos);
				evbuffer_add_printf(buf, "Number of unread queue: %d\n", ungetnum);
			}

			//查看队列状态（JSON方式，方便客服端程序处理）
			else if (strcmp(opt, "status_json") == 0)
			{
				int maxqueue = akqueue_read_maxqueue((char *)name); //最大队列数量
				int putpos = akqueue_read_putpos((char *)name); //入队列写入位置
				int getpos = akqueue_read_getpos((char *)name); //出队列读取位置
				int ungetnum;
				const char *put_times;
				const char *get_times;
				if (putpos >= getpos)
				{
					ungetnum = abs(putpos - getpos); //尚未出队列条数
					put_times = "1";
					get_times = "1";
				}
				else if (putpos < getpos)
				{
					ungetnum = abs(maxqueue - getpos + putpos); //尚未出队列条数
					put_times = "2";
					get_times = "1";
				}
				evbuffer_add_printf(buf, "{\"name\":\"%s\",\"maxqueue\":%d,\"putpos\":%d,\"putlap\":%s,\"getpos\":%d,\"getlap\":%s,\"unread\":%d}\n", name, maxqueue, putpos, put_times, getpos, get_times, ungetnum);
			}

			//查看单条队列内容
			else if (strcmp(opt, "view") == 0 && pos >= 1 && pos <= 1000000000)
			{
				char *value;
				value = akqueue_view((char *)name, pos);
				if (value)
				{
					evbuffer_add_printf(buf, "%s", value);
					free(value);
				}
				else
				{
					evbuffer_add_printf(buf, "%s", "AKQUEUE_ERROR");
				}
			}

			//重置队列
			else if (strcmp(opt, "reset") == 0)
			{
				int reset = akqueue_reset((char *)name);
				if (reset == 0)
				{
					evbuffer_add_printf(buf, "%s", "AKQUEUE_RESET_OK");
				}
				else
				{
					evbuffer_add_printf(buf, "%s", "AKQUEUE_RESET_ERROR");
				}
			}

			//设置最大的队列数量，最小值为10条，最大值为10亿条
			else if (strcmp(opt, "maxqueue") == 0 && num >= 10 && num <= 1000000000)
			{
				if (akqueue_maxqueue((char *)name, num))
				{
					//设置成功
					evbuffer_add_printf(buf, "%s", "AKQUEUE_MAXQUEUE_OK");
				}
				else
				{
					//设置取消
					evbuffer_add_printf(buf, "%s", "AKQUEUE_MAXQUEUE_CANCEL");
				}
			}

			//设置定时更新内存内容到磁盘的间隔时间，最小值为1秒，最大值为10亿秒
			else if (strcmp(opt, "synctime") == 0 && num >= 1 && num <= 1000000000)
			{
				if (akqueue_synctime(num))
				{
					//设置成功
					evbuffer_add_printf(buf, "%s", "AKQUEUE_SYNCTIME_OK");
				}
				else
				{
					//设置取消
					evbuffer_add_printf(buf, "%s", "AKQUEUE_SYNCTIME_CANCEL");
				}
			}

			else
			{
				//参数错误
				evbuffer_add_printf(buf, "%s", "AKQUEUE_ERROR");
			}

		}
		else
		{
			//参数错误
			evbuffer_add_printf(buf, "%s", "AKQUEUE_ERROR");
		}
	}

	//输出内容给客户端
    evhttp_send_reply(req, HTTP_OK, "OK", buf);	
	//内存释放
	evhttp_clear_headers(&h);
	evbuffer_free(buf);

}

int main(int argc, char *argv[], char *envp[])
{
	int ch;

	//默认参数设置/
	char *akqueue_host = "0.0.0.0";
	int  akqueue_port = 1218;
	char *akqueue_datapath = NULL;
	bool akqueue_daemon = false;
	int  akqueue_timeout = 60; //单位：秒
	akqueue_syncinterval = 5; //单位：秒
	int akqueue_cachenonleaf = 1024; //缓存非叶子节点数。单位：条
	int akqueue_cacheleaf = 2048; //缓存叶子节点数。叶子节点缓存数为非叶子节点数的两倍。单位：条
	int akqueue_mappedmemory = 104857600; //单位：字节
	akqueue_pidfile = "/tmp/akqueue.pid";
	akqueue_auth = NULL; //验证密码

	//命令行参数，暂时存储下面，便于进程重命名
	int httpsqs_prename_num = 1;
	char httpsqs_path_file[1024] = { 0 }; // httpsqs_path_file 为 httpsqs 程序的绝对路径
	struct evbuffer *httpsqs_prename_buf; //原命令行参数
	httpsqs_prename_buf = evbuffer_new();
	readlink("/proc/self/exe", httpsqs_path_file, sizeof(httpsqs_path_file));
	evbuffer_add_printf(httpsqs_prename_buf, "%s", httpsqs_path_file);
	for (httpsqs_prename_num = 1; httpsqs_prename_num < argc; httpsqs_prename_num++)
	{
		evbuffer_add_printf(httpsqs_prename_buf, " %s", argv[httpsqs_prename_num]);
	}

	//process arguments
	while((ch = getopt(argc, argv, "l:p:x:t:s:c:m:i:a:dh")) != -1)
	{
		switch(ch)
		{
		case 'l':
			akqueue_host = strdup(optarg);
			break;
		case 'p':
			akqueue_port = atoi(optarg);
			break;
		case 'x':
			akqueue_datapath = strdup(optarg); //akqueue数据文件存放路径
			if (access(akqueue_datapath, W_OK) != 0)   //如果目录不可写
			{
				if (access(akqueue_datapath, R_OK) == 0)   //如果目录可读
				{
					chmod(akqueue_datapath, S_IWOTH); //设置其他用户具可写入权限
				}
				else     //如果不存在该目录，则创建
				{
					akqueue_mkdir(akqueue_datapath);
				}

				if (access(akqueue_datapath, W_OK) != 0)   //如果目录不可写
				{
					fprintf(stderr, "akqueue datapath not writable\n");
				}
			}
			break;
		case 't':
			akqueue_timeout = atoi(optarg);
			break;
		case 's':
			akqueue_syncinterval = atoi(optarg);
			break;
		case 'c':
			akqueue_cachenonleaf = atoi(optarg);
			akqueue_cacheleaf = akqueue_cachenonleaf * 2;
			break;
		case 'm':
			akqueue_mappedmemory = atoi(optarg) * 1024 * 1024;  //单位：M
			break;
		case 'i':
			akqueue_pidfile = strdup(optarg);
			break;
		case 'a':
			akqueue_auth = strdup(optarg);
			break;
		case 'd':
			akqueue_daemon = true;
			break;
		case 'h':
		default:
			akqueue_show_menu();
			return 1;
		}
	}

	//判断是否加了必填参数 -x
	if (akqueue_datapath == NULL)
	{
		akqueue_show_menu();
		fprintf(stderr, "Attention: Please use the indispensable argument: -x <path>\n\n");
		exit(1);
	}

	//数据表路径
	char *akqueue_datafile = (char *)tccalloc(1, 1024);
	sprintf(akqueue_datafile, "%s/akqueue.db", akqueue_datapath);

	//打开数据表
	akqueue_tcbdb = tcbdbnew(); //Create a B+ tree database object
	tcbdbsetmutex(akqueue_tcbdb); //开启线程互斥锁
	tcbdbtune(akqueue_tcbdb, 1024, 2048, 50000000, 8, 10, BDBTLARGE);
	tcbdbsetcache(akqueue_tcbdb, akqueue_cacheleaf, akqueue_cachenonleaf);
	tcbdbsetxmsiz(akqueue_tcbdb, akqueue_mappedmemory); //内存缓存大小

	//判断表是否能打开
	if(!tcbdbopen(akqueue_tcbdb, akqueue_datafile, BDBOWRITER|BDBOCREAT))
	{
		//akqueue_show_menu();
		fprintf(stderr, "Attention: Unable to open the database.\n\n");
		exit(1);
	}

	//释放变量所占内存
	free(akqueue_datafile);

	//如果加了-d参数，以守护进程运行
	/* if(akqueue_daemon == true)
	{
		pid_t pid;

		//Fork off the parent process
		pid = fork();
		if(pid > 0)
		{
			exit(EXIT_SUCCESS);
		}
		else if(pid < 0)
		{
			exit(EXIT_FAILURE);
		}
	} */

	/* //将进程号写入PID文件
	FILE *fp_pidfile;
	fp_pidfile = fopen(akqueue_pidfile, "w");
	fprintf(fp_pidfile, "%d\n", getpid());
	fclose(fp_pidfile);

	//重命名httpsqs主进程，便于ps -ef命令查看
	prename_setproctitle_init(argc, argv, envp);
	prename_setproctitle("[akqueue: master process] %s", (char *)EVBUFFER_DATA(httpsqs_prename_buf));

	//派生httpsqs子进程（工作进程
	pid_t akqueue_worker_pid_wait;
	pid_t akqueue_worker_pid = fork();
	//如果派生进程失败，则退出程序
	if(akqueue_worker_pid < 0)
	{
		fprintf(stderr, "Error: %s:%d\n", __FILE__, __LINE__);
		exit(EXIT_FAILURE);
	}

	//akqueue父进程内容
	if(akqueue_worker_pid > 0)
	{
		//处理父进程接收到的kill信号

		//忽略Broken Pipe信号
		signal(SIGPIPE, SIG_IGN);

		//处理kill信号
		signal(SIGINT, kill_signal_master);
		signal(SIGKILL, kill_signal_master);
		signal(SIGQUIT, kill_signal_master);
		signal(SIGTERM, kill_signal_master);
		signal(SIGHUP, kill_signal_master);

		//处理段错误信号
		signal(SIGSEGV, kill_signal_master);

		//如果子进程终止，则重新派生新的子进程
		while (1)
		{
		    akqueue_worker_pid_wait = wait(NULL);
		    if (akqueue_worker_pid_wait < 0)
		    {
		        continue;
		    }
			usleep(100000);
		    akqueue_worker_pid = fork();
		    if (akqueue_worker_pid == 0)
		    {
		        break;
		    }
		}
	} */

	//---------------以下为httpsqs子进程内容-------------------

	//忽略Broken Pipe信号
	signal(SIGPIPE, SIG_IGN);

	//处理kill信号
	signal(SIGINT, kill_signal_worker);
	signal(SIGKILL, kill_signal_worker);
	signal(SIGQUIT, kill_signal_worker);
	signal(SIGTERM, kill_signal_worker);
	signal(SIGHUP, kill_signal_worker);

	//处理段错误信号
	signal(SIGSEGV, kill_signal_worker);

	//创建定时同步线程，定时将内存中的内容写入磁盘
	pthread_t sync_worker_tid;
	pthread_create(&sync_worker_tid, NULL, (void *) sync_worker, NULL);
	/*
		//重命名httpsqs子进程，便于ps -ef命令查看
		prename_setproctitle_init(argc, argv, envp);
		prename_setproctitle("[akqueue: worker process] %s", (char *)EVBUFFER_DATA(httpsqs_prename_buf));
		evbuffer_free(httpsqs_prename_buf); */

	//请求处理部分
	struct evhttp *httpd;

	event_init();
	httpd = evhttp_start(akqueue_host, akqueue_port);

	if (httpd == NULL)
	{
		fprintf(stderr, "Error: Unable to listen on %s:%d\n\n", akqueue_host, akqueue_port);
		kill(0, SIGTERM);
		exit(1);
	}

	evhttp_set_timeout(httpd, akqueue_timeout);
	evhttp_set_gencb(httpd, http_handler, NULL);
	event_dispatch();
	evhttp_free(httpd);




	//fprintf(stderr, "ok2\n");
	return 0;








}
